package com.domainlanguage;

import com.domainlanguage.base.Ratio;
import com.domainlanguage.money.Money;
import com.domainlanguage.time.*;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.Type;

import javax.persistence.*;

@SuppressWarnings({"UnusedDeclaration"})
@Entity
public class AllTypes {

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Type(type = "com.domainlanguage.time.CalendarDateType")
    private CalendarDate calendarDate;

    @Type(type = "com.domainlanguage.time.CalendarIntervalType")
    private CalendarInterval calendarInterval;

    @Type(type = "com.domainlanguage.time.CalendarMinuteType")
    private CalendarMinute calendarMinute;

    @Type(type = "com.domainlanguage.time.DurationType")
    private Duration duration;

    @Type(type = "com.domainlanguage.time.HourOfDayType")
    private HourOfDay hourOfDay;

    @Type(type = "com.domainlanguage.time.MinuteOfHourType")
    private MinuteOfHour minuteOfHour;

    @Type(type = "com.domainlanguage.time.RawTimeIntervalType")
    private TimeInterval rawTimeInterval;

    @Type(type = "com.domainlanguage.time.ParameterizedTimeIntervalType", parameters = {
        @Parameter(name = "closedStart", value = "false"),
        @Parameter(name = "closedEnd", value = "true")
    })
    private TimeInterval timeInterval;

    @Type(type = "com.domainlanguage.time.TimeOfDayType")
    private TimeOfDay timeOfDay;

    @Type(type = "com.domainlanguage.time.TimePointType")
    // Use this for databases that don't have millisecond precision for timestamp (MySQL)
    //@Type(type = "com.domainlanguage.time.BigIntTimePointType")
    private TimePoint timePoint;

    @Type(type = "com.domainlanguage.time.TimeRateType")
    private TimeRate timeRate;

    @Type(type = "com.domainlanguage.time.TimeUnitType")
    @Column(length = 11)
    private TimeUnit timeUnit;

    @Type(type = "com.domainlanguage.time.CalendarDateType")
    @AttributeOverrides({
        @AttributeOverride(name = "amount", column = @Column(name = "amount", precision = 20, scale = 4)),
        @AttributeOverride(name = "currency", column = @Column(name = "currency"))
    })
    private Money money;

    @Type(type = "com.domainlanguage.time.CalendarDateType")
    private Ratio ratio;

    public AllTypes() {
    }

    public AllTypes(TimePoint timePoint,
                    Duration duration,
                    CalendarDate calendarDate,
                    CalendarMinute calendarMinute,
                    TimeOfDay timeOfDay,
                    HourOfDay hourOfDay,
                    MinuteOfHour minuteOfHour,
                    TimeRate timeRate,
                    TimeUnit timeUnit,
                    TimeInterval rawTimeInterval,
                    TimeInterval timeInterval,
                    CalendarInterval calendarInterval,
                    Money money,
                    Ratio ratio) {
        this.timePoint = timePoint;
        this.duration = duration;
        this.calendarDate = calendarDate;
        this.calendarMinute = calendarMinute;
        this.timeOfDay = timeOfDay;
        this.hourOfDay = hourOfDay;
        this.minuteOfHour = minuteOfHour;
        this.timeRate = timeRate;
        this.timeUnit = timeUnit;
        this.rawTimeInterval = rawTimeInterval;
        this.timeInterval = timeInterval;
        this.calendarInterval = calendarInterval;
        this.money = money;
        this.ratio = ratio;
    }

    public Long getId() {
        return id;
    }

    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this);
    }

    @Override
    public boolean equals(Object other) {
        return EqualsBuilder.reflectionEquals(this, other);
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
    }
}
